<!doctype html>
<html lang="en">
<head>
    <meta charset="UTF-8">
    <meta name="viewport"
          content="width=device-width, user-scalable=no, initial-scale=1.0, maximum-scale=1.0, minimum-scale=1.0">
    <meta http-equiv="X-UA-Compatible" content="ie=edge">
    <title>Document</title>
</head>
<body>
<ul>
    <li>123</li>
    <li>234</li>
    <li>345</li>
    <li>wed</li>
    <li>wedxs</li>
</ul>
<script>
    /*
    * 1.
    * push pop shift unshift等方法
    *   参数 返回值
    *   封装
    * */

    /*
    * forEach方法 基础模板
    *   功能：遍历数组 拿到每一项进行操作
    *   接收一个参数：回调函数
    *   回调函数的操作核心：对数组的每一项 下标 数组本身进行操作
    *       三个参数（形参）：item    index   arr 这三项需要用到哪些就写哪些
    *   回调函数有返回吗 需要返回值吗？ 回调函数不需要返回值 因为forEach只接收参数 对参数进行操作就可以了
    *
    * */
    let arr = [1,2,3]
    //情况一
    arr.forEach(function (item){ //形参
        item++ //这里第一次遍历数组将里面的1遍历出来 上面的形参item就等于第一项arr[0]里面的值1 第二次item就等于第二项arr[1]里面的值2
    })         //总的来说就是一个赋值操作 抄作业
    console.log(arr) //值类型 所以此时并不会改变原数组
    //情况二
    arr.forEach(function (item,index,arr){ //写了三个形参 arr形参查询变量的时候先从内部寻找，即从内往外
        arr[index]++ //通过数组arr找到每一个下标index所对应的值item 从而进行++操作 达到对数组里面的属性进行修改
    })
    console.log(arr) //引用类型 此时数组的内部属性就变成[2,3,4]

    //情况三
    let arr1 = [
        {v:1},
        {v:2},
        {v:3}
    ]

    arr.forEach((item) => { //item所对应的就是数组里面的每一个对象{v:1} {v:2} {v:3}
        item.v++ // 对数组里面的对象的属性进行修改 此时数组中遍历到的 每个对象 里面的属性值都进行了++操作
    })
    console.log(arr1) //现在是引用类型 因为数组里面是对象 即[{v:2},{v:3},{v:4}]

    /*
    * 从这里开始所学的数组方法都是建立在forEach基础之上的
    * every
    *   判断是否每一项都满足条件 类似于 与判断 && 电路串联关系
    *   如果每一项都满足 整体返回true
    *   否则只要有一项不满足 整体返回false
    *
    *   every语法：
    *   参数：接收一个回调函数作为参数，而回调函数接收三个参数：item index arr 但是回调函数多了一个返回值(布尔值) true/false
    *       当返回true 表示单项满足条件；返回false 表示单项不满足条件(注意这里的返回值是回调函数的返回值 回调函数一次只能对一项进行操作)
    *
    *   every的返回值 布尔值 （请特别注意every的返回值 和 回调函数的返回值 是两种不同情况）
    *       当返回true 表示所有项都满足条件
    *       返回false 表示存在不满足条件的项
    *
    * */

    let teachers = [
        {
            name:"阿飞",
            age:20
        },
        {
            name:"银时",
            age:19
        },
        {
            name:"云牧",
            age:22
        },
        {
            name:"sherry",
            age:17
        }
    ]

    //需求：判断是否所有的元素的 age属性 是否都大于18岁 都满足 返回true 否则返回false

    //以往我们的写法及思路：
    let result = true //先假设都满足 结果为true
    //循环遍历 一旦发现不满足 结果改成false
    //最后输出结果

    for(let i = 0;i < teachers.length;i++) {
        if(teachers[i].age < 18){
            result = false
            break
        }
    }
    console.log(result)

    //现在用every方法
    let result1 = teachers.every(teachers => teachers.age > 18) //拿到teachers数组 对里面每一个{}进行判断 里面age属性是否满足
    console.log(result1)

    //every可以改写成：
    function older(person){ //形参person
        return person.age > 18 //对遍历拿到的每一个单项进行判断
    }

    teachers.every(older) //将every从数组teachers中遍历到的每一个对象的值传递到older函数中进行操作判断 只要其中有一项不满足 整体就会返回false


    //做一个病毒检测流程
    let arr2 = ["12w","wdx","234病毒78","nisdc","586","92dte"]

    function check(str){
        return !str.includes("病毒") //不包含病毒返回true 包含返回false
    }

    console.log(arr2.every(check)) //将every从数组中遍历到的每个单项传入check函数中进行一一判断 全部满足条件返回true 只要有一个不满足就返回false
    /*
    * 这里要明白回调函数check在做什么 every又在做什么 两者有啥联系
    * 1.回调函数 将arr中每个字符串做一次检测判断 第一个字符串不包含 返回true；第二个不包含 返回true；第三个包含 返回false以此类推
    * 2.every将回调函数所检测到的所有结果 无论是true还是false都收集到一起 进行判断 全部满足条件（全部结果都为true）就为true 否则false
    * */


    //判断数组中的每一项是不是都是字符串

    let arr3 = ["25","90j"]

    function strCheck(item){
        return typeof item === "string"
    }

    console.log(arr3.every(strCheck))

    //或者这样
    console.log(arr3.every(item => typeof item === "string"))

    //下面代码是什么含义
    s = arr3.every(item => typeof item !== "string")
    //数组arr3 里面的每一项item 的类型    都不是  字符串
    //返回true 就表示数组里面的每一位元素的类型都不是字符串
    //返回false 表示数组里面包含有类型是字符串的元素  每个都是 的反面是 不都是


    /*
    * some
    *   只要有一个满足条件 整体就返回true 类似于 或判断 || 电路并联关系
    *   每一项都不满足 整体才返回false
    *
    *   参数：接收一个回调函数作为参数
    *       回调函数 接收三个参数 item index arr 回调函数有返回值 返回布尔值 true单项满足/false单项不满足
    *
    *   some的返回值：true表示至少有一个满足条件  false表示全部都不满足 全军覆没
    *
    * */

    let students = [true,true,false,true,true]

    function check1(item){
        return item === true
    }

    students.every(check1) //返回true 数组里面表示每一项都为true；返回false 表示至少有一项为false
    students.some(check1) //返回true 表示数组里面至少有一项为true；返回false 表示全部项都为false


    let liList = document.querySelectorAll("ul li") //此时liList不是一个数组
    let every = [].every.bind(liList) //拿到数组的every方法 绑定到liList中
    let some = [].some.bind(liList) //拿到数组的some方法 绑定到liList中

    //判断是否所有的li里面都有内容（全部 -> true）
    every(li => li.innerHTML.length > 0) //true 全部都有内容；false 至少有一项为空

    //判断是否所有的li里面存在没有内容的（存在 -> true）
    some(li => li.innerHTML === "") //true 代表有空的；false 全部都有内容


    /*
    * 筛选满足条件的内容元素
    * filter 过滤 筛选
    *   参数：接收一个回调函数 这个回调函数就是筛选条件
    *       回调函数接收三个参数 item index arr
    *       回调函数有返回值 返回true 表示保留；返回false 表示剔除
    *
    *   filter返回值：返回一个由回调函数所筛选出的所有内容所组成的全新的数组
    *
    * filter的使用场景：数组，根据条件找出部分元素，都可以用filter
    *
    * */

    let arr5 = [1,"2","3",4,{},[],undefined]
    //将所有字符串抽离出来单独形成一个数组

    function filterMethod(item){
        return typeof  item === "string"
    }

    let result2 = arr5.filter(filterMethod)
    console.log(result2)


    let arr6 = [1,"2",-1,3,"-3"]
    //筛选所有大于零的数字
    let result3 = arr.filter(item => {return typeof item === "number" && item > 0})
    console.log(result3)


    /*
    * 水仙花数：
    * */

    let arr7 = []
    for(let i = 100;i < 1000;i++){
        arr7.push(i) //将100到999全部传入数组
    }

    let re = arr7.filter(num => {
        let str = `${num}` //强行将数字转换成字符串
        return str[0] ** 3 + str[1] ** 3 +str[2] ** 3 === num
    })

    console.log(re)


    /*
    * 小结：四个api方法
    *
    * 1.api的功能，主要用于解决什么问题
    *   forEach 遍历数组所有项
    *   every 判断数组是否所有项都满足
    *   some 判断数组是否有至少一项满足
    *   filter 筛选数组中满足条件的项，组成新的数组
    *
    * 2.api方法有无返回值；回调函数有无返回值；回调函数的返回值与api方法的返回值之间的联系影响
    *   forEach 没有返回值
    *
    *   every 有返回值true全部项满足/false有不满足项 回调函数有返回值true单项满足/false单项不满足
    *         回调函数返回的所有单项都为true则every的返回值为true 回调函数返回的单项中若有一项为false则every的返回值为false
    *
    *   some 有返回值true有满足项/false全部项都不满足 回调函数有返回值true单项满足/false单项不满足
    *        回调函数返回的所有单项只要有一项为true则every的返回值为true 回调函数返回的所有单项为false则every的返回值为false
    *
    *   filter 有返回值返回全新的数组 回调函数有返回值true表示单项保留/false表示单项删除
    *          回调函数返回的true项将被筛选保留进filter返回的全新数组中
    *
    *   以上所有方法都接收一个回调函数->回调函数都接收三个参数->item单项元素 index单项元素的下标 arr所有单项元素所组成的数组
    *
    * 3.api整体返回的结果是什么，即api返回值的具体意义，参考上面的2
    *
    *
    * */

    /*
    * 封装forEach
    *   接收参数：两个参数 -> 数组arr 回调函数callback
    *   没有返回值
    *   功能：拿出数组里的每一项 给回调函数执行
    * */

    function myForEach(arr,callback){
        for(let i = 0;i < arr.length;i++){
            callback(arr[i],i,arr) //将数组中每一项的下标 数组中每一项的内容 数组 作为参数传给回调函数callback
        }
    }

    let ai = ["我","爱","你"]
    myForEach(ai,function (item,index,arr){console.log(item)}) //这个是自己封装的forEach方法的使用
    ai.forEach(item => {console.log(item)}) //这个是数组forEach方法使用箭头函数 注意与上方函数功能一样 只是调用的形式不一样
    ai.forEach(function (item,index,arr){ //这个是数组forEach方法使用普通函数
        console.log(item)
    })


    /*
    * 封装every方法
    *   接收参数：arr callback
    *   返回值：callback返回单项判断布尔值 整体返回所有项判断布尔值
    *   功能：判断数组所有项是否都满足
    * */

    function myEvery(arr,callback){
        for(let i = 0;i < arr.length;i++){
            if(!callback(arr[i],i,arr)){ //为什么只写不满足的情况 因为我们的要求就是只要有一个单项不满足 函数every整体就返回false
                return false //注意这里的返回值是整体函数every的返回值 不是回调函数的返回值 因为我们根本没有声明定义回调函数 只是将其作为参数与判断条件
            } //所以这里的return false表示只要回调函数有一次循环不满足条件 整体的函数every的返回值就返回false 就结束了整个函数
        }//因为我们只在循环里面写了一个只要有一项不满足整体的返回是false 并没有写如果全部都满足要返回什么 所以要在循环外面再写一个关于整体全都满足的返回值
         //参考every的特性 参数回调函数返回的所有为true every整体才能返回true；参数回调函数只要有一个返回false every整体就只能返回false
         //为什么整体全部都满足的情况返回true要写在循环外面 因为循环条件为真 循环就会一直执行下去 写在循环里面 没执行一次就返回一个true
         //这样返回的true就不能达到我们要表示如果全部单项都满足整体函数every就返回一个true的要求 而会变成是一项满足就返回一个true的莫名其妙
        return true //这里表示否则就返回true 即补全上面的如果所有单项都满足回调函数的条件 即我们省略的回调函数单次为true的判断 函数every整体的返回值返回true
    } //这里要对callback函数要有一个非常清晰的认识
    // callback函数并不是内部自带的函数 我们并未也并不需要现在声明定义它 只需要在执行every函数时将其作为参数传入时再具体声明定义即可
    // 具体使用看下面
    let s1 = myEvery([1,2,3],function (item){ //瞧，回调函数是这个时候具体声明的
        if(item < 5) return true //这个就是回调函数的返回值
    })//整体函数every执行也会有一个返回值 而这个返回值是看里面回调函数的返回值情况决定的 将整体函数的返回值赋值给s1打印
    console.log(s1)


    /*
    * 封装some方法
    *   接收参数：arr callback
    *   返回值：callback返回单项判断布尔值 整体返回所有项判断布尔值
    *   功能：判断数组是否存在有单项（至少一项）满足条件
    * */

    function mySome(arr,callback){
        for (let i = 0;i < arr.length;i++){
            if(callback(arr[i],i,arr)){ //只要有一项满足条件 some函数整体返回值就返回true 结束整个函数 进入了这里就不用看下面返回false的情况
                return true
            }
        }
        return false //表示上面全部单项都不满足条件 全都为false 则some函数整体返回值就返回false 结束函数
    } //这个方法仅仅只是改变了和every的判断条件 两者可以进行对比参考



    /*
    * 封装filter方法
    *   接收参数：arr callback
    *   返回值：callback返回单项判断布尔值 整体返回所有被 callback函数 判断布尔值为true的项 所组成的新数组
    *   功能：筛选数组中满足条件的元素 将筛选出来的元素组成一个新数组返回出来
    * */

    function myFilter(arr,callback){
        let result = []
        for(i = 0;i < arr.length;i++){
            if(callback(arr[i],i,arr)){
                result.push(arr[i]) //只需将满足条件的项的添加到新数组中
            } //不用管不满足的项 直到没有满足的项循环就结束了
        }
        return result //函数filter整体返回筛选后的新数组 筛选了多少就返回多少 如果数组没有内容或者没有满足项 就不会进入for循环 直接输出结果数组
                      //如果进入了for循环且循环完所有满足项 也返回总体筛选的结果
    }

    let ab = [1,2,3,4,5,6,7,8,9,10]
    let s3 = myFilter(ab,function (item,index,arr){
        return item % 2 !== 0 //筛选所有奇数
    })
    let s4 = myFilter(ab,(item) => {
        return item % 2 === 0 //筛选所有偶数
    })
    console.log(s3,s4)


</script>
</body>
</html>